//******************************************************************
//******************************************************************
//**********          ANts Peer To Peer Sources        *************
//
// ANts P2P realizes a third generation P2P net. It protects your
// privacy while you are connected and makes you not trackable, hiding
// your identity (ip) and crypting everything you are sending/receiving
// from others.

// Copyright (C) 2004  Roberto Rossi

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

package ants.p2p.query;

import ants.p2p.*;
import ants.p2p.Router;
import ants.p2p.Message;
import ants.p2p.utils.misc.Random;
import java.util.ArrayList;
import ants.p2p.query.security.PublicHeader;

public class QueryMessage extends Message {
  QueryNode query;
  ArrayList tuples;
  PublicHeader ph;
  boolean processed = false;
  Random rnd = new Random(System.currentTimeMillis());
  long localQueryId;

  private static long localQueryIDCounter = (long)Math.floor(Math.random()*100000000);

  public QueryMessage(Message m, QueryNode query, PublicHeader ph) {
    super(m);
    this.tuples = new ArrayList();
    this.ph = ph;
    this.query = query;
    this.localQueryId = nextLocalQueryID();
    this.initializeRnd();
  }

  public QueryMessage(QueryMessage qm) {
    super(qm);
    this.tuples = (ArrayList)qm.tuples.clone();
    this.ph = qm.ph;
    this.query = qm.query;
    this.localQueryId = qm.localQueryId;
    this.rnd = qm.rnd;
  }

  public QueryMessage(QueryNode query, PublicHeader ph) {
    super();
    this.tuples = new ArrayList();
    this.ph = ph;
    this.query = query;
    this.localQueryId = nextLocalQueryID();
    this.initializeRnd();
  }

  public void setNewDest(String newDest){
    this.dest = newDest;
  }

  public QueryNode getQuery(){
    return this.query;
  }

  private void initializeRnd(){
    for(int x = 0; x < Router.initialRounds; x++){
      rnd.nextDouble();
    }
  }

  public double getNextRandomDouble(){
    return this.rnd.nextDouble();
  }

  public double getNextRandomDoubleAndRollback(){
    long oldSeed = rnd.getSeed();
    double temp = rnd.nextDouble();
    this.rnd.setSeed(oldSeed);
    return temp;
  }

  public ArrayList getTuples(){
    return this.tuples;
  }

  public void resetTuples(){
    this.tuples = new ArrayList();
  }

  public PublicHeader getPublicHeader(){
    return this.ph;
  }

  public void setProcessed(){
    this.processed=true;
  }

  public boolean getProcessed(){
    return this.processed;
  }

  public long getLocalQueryId(){
    return this.localQueryId;
  }

  public static long nextLocalQueryID(){
    return localQueryIDCounter++;
  }

  public Message getSignableMessage(){
    try{
      QueryMessage signable = (QueryMessage)super.getSignableMessage();
      signable.rnd = null;
      signable.dest = null;
      return signable;
    }catch(Exception e){
      e.printStackTrace();
      return null;
    }
  }

  public boolean equals(Object o) {
    if (o instanceof MessageWrapper) {
      return ( (MessageWrapper) o).getMessage().getAck_Id().equals(this.getAck_Id()) &&
          ( (MessageWrapper) o).getMessage().getType() == this.getType() &&
          ( (MessageWrapper) o).getMessage().getDest() == this.getDest();
    }
    else{
      try {
        return ( (Message) o).getAck_Id().equals(this.getAck_Id()) &&
            ( (Message) o).getType() == this.getType() &&
            ( (Message) o).getDest() == this.getDest();
      }
      catch (ClassCastException e) {
        return o == this;
      }
    }
  }
}
